package com.bolt.admin.module.sys.service;

import com.bolt.admin.exception.BizExceptionEnum;
import com.bolt.admin.module.sys.dto.RoleDTO;
import com.bolt.admin.module.sys.dto.converter.RoleConverter;
import com.bolt.admin.module.sys.entity.*;
import com.bolt.admin.module.sys.repository.RoleRepository;
import com.bolt.common.collection.IteratorUtil;
import com.bolt.common.utils.ArrayUtil;
import com.bolt.convention.exception.ServiceException;
import com.bolt.core.view.components.FormItem;
import com.bolt.core.view.components.ListDataLoad;
import com.bolt.support.base.service.BaseService;
import com.bolt.support.cache.redis.RedisManager;
import com.bolt.support.spring.jpa.jpql.Clauses;
import com.bolt.support.spring.jpa.repository.BasicJpaRepository;
import com.bolt.support.ui.tree.vo.UITreeNode;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * Auto Generate Javadoc
 *
 * @author 日期:2018-02-26 17:21:27
 *         角色信息
 **/
@Service
@Transactional(readOnly = true, rollbackFor = Exception.class)
@RequiredArgsConstructor
public class RoleService extends BaseService <RoleEntity, String> implements ListDataLoad {

    private final RoleRepository roleRepository;

    private final PrivilegeService privilegeService;

    private final MenuService menuService;

    private final RedisManager redisManager;

    @Override
    protected BasicJpaRepository <RoleEntity, String> getRepository() {
        return roleRepository;
    }

    public List <PrivilegeEntity> findRoleButtonByMenuId(String roleId, Long menuId) {
        List <PrivilegeEntity> roleButton = privilegeService.findButtonPrivileges(roleId);
        List <PrivilegeEntity> allButton = privilegeService.findMenuButtonPrivilege(menuId);
        for (PrivilegeEntity button : allButton) {
            button.setRelated(false);
            for (PrivilegeEntity p2 : roleButton) {
                if (p2.equals(button)) {
                    button.setRelated(true);
                    break;
                }
            }
        }
        return allButton;
    }


    /**
     * 只做菜单权限
     *
     * @param roleId       角色ID
     * @param checkMenuIds 选中菜单ID
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateRelatedPrivilegeR2s(String roleId, Long[] checkMenuIds) {
        try {
            Optional <RoleEntity> optional = findOne(roleId);
            if (optional.isPresent()) {
                RoleEntity entity = optional.get();
                List <String> privilegeIds = privilegeService.findIdsBymenuIds(checkMenuIds);
                String[] ids = privilegeIds.toArray(new String[0]);
                updateRelatedR2s(entity, ids, "roleR2Privileges", "privilege");
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    /**
     * 带按钮的权限分配
     *
     * @param roleId        角色ID
     * @param checkMenuIds  选中菜单ID
     * @param cancelItems   取消菜单ID
     * @param currentMenuId 当前菜单ID
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateRelatedPrivilege(String roleId, Long[] checkMenuIds, String[] cancelItems, Long currentMenuId) {
        RoleEntity entity = findOne(roleId).orElseThrow(() -> new ServiceException(BizExceptionEnum.DATA_NOT_FIND));
        List <RoleR2Privilege> r2ps = entity.getRoleR2Privileges();
        //删除全部时的情况
        if (ArrayUtil.isEmpty(checkMenuIds)) {
            updateRelatedR2s(entity, null, "roleR2Privileges", "privilege");
        }
        //处理修改时情况
        if (ArrayUtil.isEmpty(cancelItems) && IteratorUtil.isNotEmpty(r2ps)) {
            List <Long> roleMenuIds = new ArrayList();
            List <String> menuPrivilegeIds = privilegeService.findIdsBymenuIds(checkMenuIds, PrivilegeEntity.PrivilegeTypeEnum.URL);
            for (RoleR2Privilege r2p : r2ps) {
                if (ArrayUtil.contains(checkMenuIds, r2p.getPrivilege().getMenuId())
                        && (r2p.getPrivilege().getType() == PrivilegeEntity.PrivilegeTypeEnum.BUTTON)) {
                    menuPrivilegeIds.add(r2p.getPrivilege().getId());
                }
                roleMenuIds.add(r2p.getPrivilege().getMenuId());
            }
            List <Long> addMenuIds = new ArrayList();
            for (Long menId : checkMenuIds) {
                if (!roleMenuIds.contains(menId)) {
                    addMenuIds.add(menId);
                }
            }
            addMenuIds.add(currentMenuId);
            if (IteratorUtil.isNotEmpty(addMenuIds)) {
                List <String> buttonPrivilegeIds =
                        privilegeService.findIdsBymenuIds(addMenuIds.toArray(new Long[0]), PrivilegeEntity.PrivilegeTypeEnum.BUTTON);
                menuPrivilegeIds.addAll(buttonPrivilegeIds);
            }

            String[] ids = menuPrivilegeIds.toArray(new String[0]);
            updateRelatedR2s(entity, ids, "roleR2Privileges", "privilege");
        } else {
            List <String> privielgeIds = privilegeService.findIdsBymenuIds(checkMenuIds);
            for (String id : cancelItems) {
                if (privielgeIds.contains(id)) {
                    privielgeIds.remove(id);
                }
            }
            String[] ids = privielgeIds.toArray(new String[0]);
            updateRelatedR2s(entity, ids, "roleR2Privileges", "privilege");
        }

    }

    public RoleEntity updateRelatedPrivilege(String roleId, Long[] checkMenuIds) {
        Optional <RoleEntity> optional = findOne(roleId);
        RoleEntity entity = null;
        if (optional.isPresent()) {
            entity = optional.get();
            List <String> privilegeIds = privilegeService.findIdsBymenuIds(checkMenuIds);
            String[] ids = privilegeIds.toArray(new String[0]);
            updateRelatedR2s(entity, ids, "roleR2Privileges", "privilege");
            for (UserR2Role userR2RoleEntity : entity.getRoleR2Users()) {
                redisManager.del( userR2RoleEntity.getUser().getId());
            }
        }
        return entity;
    }



    @Override
    public Map <String, String> load(FormItem formItem, Map  map) {
        Map <String, String> data = new LinkedHashMap <>();
        List <Object[]> roles = roleRepository.findAllRoleItem();
        for (Object[] role : roles) {
            data.put((String) role[0], (String) role[1]);
        }
        return data;
    }

    public List <RoleDTO> getAllRoleData() {
        return this.jpaQueryFactory.select(RoleDTO.class,
                Clauses.of(RoleEntity::getId),
                Clauses.of(RoleEntity::getName)
        ).from(Clauses.of(RoleEntity.class))
                .orderBy(Clauses.of(RoleEntity::getCode).desc()).fetch();
    }

    public List <UITreeNode> getSimpleMenuTree(String id) {
        RoleEntity role = findOne(id).get();
        List <Long> privilegeMenuIds = role.getPrivilegeMenuIds();
        List <MenuEntity> menus = menuService.findAllCached();
        List <UITreeNode> simpleMenu = new ArrayList <>();
        for (MenuEntity menu : menus) {
            UITreeNode treeNode = new UITreeNode();
            treeNode.setName(menu.getName());
            treeNode.setId(String.valueOf(menu.getId()));
            treeNode.setPId(String.valueOf(menu.getPid()));
            treeNode.setParent(menu.hasChildren());
            if (IteratorUtil.isNotEmpty(privilegeMenuIds)) {
                treeNode.setChecked(privilegeMenuIds.contains(menu.getId()));
            }
            simpleMenu.add(treeNode);
        }
        return simpleMenu;
    }

    public List <RoleEntity> findRoles(UserEntity user) {
        return roleRepository.findRolesByUser(user);
    }

    @Transactional(rollbackFor = Exception.class)
    public RoleEntity saveOrUpdate(RoleDTO dto) {
        RoleEntity entity = RoleConverter.toEntity(dto);
        save(entity);
        return entity;
    }

}
